#include "FeederAgent.h"
#include "ScopedLock.h"

	
	// Constructor needs to be passed its name, reference to the gantry, reference to top lane and
	// bottom lane and the guifeeder. 

	/**
	 * @fn	FeederAgent::FeederAgent(std::string myname)
	 *
	 * @brief	Constructor.
	 *
	 * @author	Graham Matuszewski
	 *
	 * @param	myname			  	The myname.
	 * @param [in,out]	newGantry 	If non-null, the new gantry.
	 * @param [in,out]	laneTop   	If non-null, the lane top.
	 * @param [in,out]	laneBottom	If non-null, the lane bottom.
	 * @param [in,out]	gui		  	If non-null, the graphical user interface.
	 */


	FeederAgent::FeederAgent(std::string myname):Agent(myname) {
		
		//INITIALIZE
		
		//name=myname;
		//gantry=new GantryAgent("idk");
	//	topLane = laneTop;
	//	bottomLane = laneBottom;
//		guiFeeder = gui;
		state=IDLE;
		giveGantryStatus=false;
		partOrders = new std::list<PartRecipe>();
	}

	//MESSAGE RECIEVED From Nest TO TELL IS TO GO GET NEW PARTS, EVENTUALLY MESSAGE WILL TELL GANTRY

	/**
	 * @fn	void FeederAgent::msgPleaseGetParts(PartType newPartType, LaneAgent* newLane)
	 *
	 * @brief	Message please get parts.
	 *
	 * @author	Graham Matuszewski
	 *
	 * @param	newPartType	   	Type of the new part.
	 * @param [in,out]	newLane	If non-null, the new lane.
	 */

	void FeederAgent::msgPleaseGetParts(PartType newPartType, Lane* newLane){
		PartRecipe temp;
		temp.partType=newPartType;

		if(newLane == topLane){
			temp.topLane=true;
			currentLane=true;
		} else {
			temp.topLane=false;
			currentLane=false;
		}

		if(state!=FeederStatus::IDLE)
			state=FeederStatus::PURGE;
	
		//ADD IT TO THE LIST
		{
		ScopedLock scopedFeederNeededListLock (&FeederLock);
		partOrders->push_back(temp);
		}
		Do(" Feeder Agent has recieved message msgPleaseGetParts");
		stateChanged();
	}

	//MESSAGE FROM THE FEEDER TO TELL IT THAT IT NOW HAS PARTS, ITS GIVEN THE RECIPE FOR THE PART

	/**
	 * @fn	void FeederAgent::msgHereAreParts(PartRecipe recipe)
	 *
	 * @brief	Message here are parts.
	 *
	 * @author	Graham Matuszewski
	 *
	 * @param	recipe	The recipe.
	 */

	void FeederAgent::msgHereAreParts(PartRecipe recipe){
		//recipe.topLane=currentLane;
		currentRecipe=recipe;
		state=MOVING;
		Do(" Feeder Agent has recieved message msgHereAreParts");
		stateChanged();
	}

	//MESSAGE FROM GUI THAT THE PART HAS BEGUN BEING MOVED TO THE LANE

	/**
	 * @fn	void FeederAgent::msgGUIHasMovedPart()
	 *
	 * @brief	Message graphical user interface has moved part.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::msgGUIHasMovedPart(){
		state=IDLE;
		Do(" Feeder Agent has recieved message msgGUIHasMovedPart");
		stateChanged();
	}

	//message from gantry to ask whether it still has parts

	/**
	 * @fn	void FeederAgent::msgCurrentState()
	 *
	 * @brief	Message current state.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::msgCurrentStatus(){
		giveGantryStatus=true;
		print(" Feeder Agent has recieved message msgCurrentStatus");
		stateChanged();
	}
	//MESSAGE FROM LANE?

	/**
	 * @fn	void FeederAgent::msgPurgeParts()
	 *
	 * @brief	Message purge parts.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::msgPurgeParts(){
		state=PURGE;
		Do(" Feeder Agent has recieved message msgPurgeParts");
		stateChanged();
	}

	/**
	 * @fn	void FeederAgent::msgGUIHasPurged()
	 *
	 * @brief	Message graphical user interface has purged.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::msgGUIHasPurged(){
		state=IDLE;
		giveGantryStatus=true;
		Do(" Feeder Agent has recieved message msgGUIHasPurged");
		stateChanged();
	}
	
	//SCHEDULER

	/**
	 * @fn	bool FeederAgent::pickAndExecuteAnAction()
	 *
	 * @brief	Gets the pick and execute an action.
	 *
	 * @author	Graham Matuszewski
	 *
	 * @return	true if it succeeds, false if it fails.
	 */

	bool FeederAgent::pickAndExecuteAnAction(){
		if(state==PURGE){
			notifyPurge();
			return true;
		}
		if(partOrders->size()>0){
			notifyGantry();
			//print("scheduler fires");
			return true;
		}
		if(state==MOVING){
			moveGuiToLane();
			return true;
		}
		if(giveGantryStatus && state==IDLE){
			giveStatusToGantry();
			return true;
		}
		return false;
	}
	//ACTIONS

	/**
	 * @fn	void FeederAgent::notifyPurge()
	 *
	 * @brief	Notifies the purge.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::notifyPurge(){
		state=IDLE;
		if(guiFeeder!=NULL)
			guiFeeder->DoPurge();
		Do(this->toString() + " Has begun Purge Process");
	}

	/**
	 * @fn	void FeederAgent::notifyGantry()
	 *
	 * @brief	Notifies the gantry.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::notifyGantry()
	{
		{
			ScopedLock scopedFeederNeededListLock (&FeederLock);
			PartRecipe temp = (partOrders->front());
			partOrders->pop_front();
			gantry->msgPleaseGetParts(temp,this);

		}
		Do(this->toString() + " is calling gantry msgPleaseGetParts");
	}

	/**
	 * @fn	void FeederAgent::moveGuiToLane()
	 *
	 * @brief	Move graphical user interface to lane.
	 *
	 * @author	Graham Matuszewski
	 */

	void FeederAgent::moveGuiToLane(){
		state=GUI;
		if(currentRecipe.topLane){
			if(guiFeeder!=NULL)
				guiFeeder->DoDropInLane(1); //assuming 1 means gui gets it top
			topLane->msgHereAreParts(currentRecipe.partType);
			Do(this->toString() + " Has Told the GUIFeeder to begin dropping parts in topLane");
		} else { 
			if(guiFeeder!=NULL)
				guiFeeder->DoDropInLane(0);
			bottomLane->msgHereAreParts(currentRecipe.partType);
			Do(this->toString() + " Has Told the GUIFeeder to begin dropping parts in bottomLane");
		}	
		
	}
	void FeederAgent::giveStatusToGantry(){
		giveGantryStatus=false;
		gantry->msgFeederStatus(this,false);
		Do(this->toString() + " Has Told the Gantry whether the Feeder has parts or not");
	}

	/**
	 * @fn	std::string FeederAgent::toString() const
	 *
	 * @brief	Convert this object into a string representation.
	 *
	 * @author	Graham Matuszewski
	 *
	 * @return	A string representation of this object.
	 */


	void FeederAgent::setGantry(Gantry* newGantry){
		gantry=newGantry;
	}
	void FeederAgent::setLaneTop(Lane* laneTop){
		topLane=laneTop;
	}
	void FeederAgent::setLaneBottom(Lane* laneBottom){
		bottomLane=laneBottom;
	}
	void FeederAgent::setGUIFeeder(GUIFeeder* gui){
		guiFeeder=gui;
	}
	// 
	Gantry* FeederAgent::getGantryAgent(){
		return gantry;
	}
	
	Lane* FeederAgent::getBottomAgent(){
		return bottomLane; 
	}
	Lane* FeederAgent::getTopAgent(){
		return topLane;
		
	}
	

	std::string FeederAgent::toString() const
	{
		return "FeederAgent " + getName();
	}

	GUIFeeder* FeederAgent::getGUI(){
		return guiFeeder;
	}
	int FeederAgent::partOrdersSize(){
		return partOrders->size();
	}


	PartRecipe FeederAgent::getTopRecipe(){
		return partOrders->front();
	}


	void FeederAgent::handleBreak(){
		guiFeeder->DoBreak();
	}
	void FeederAgent::handleFix(){
		guiFeeder->DoFix();
	}



